<!DOCTYPE html>
<html>
<head>
	<!-- Global site tag (gtag.js) - Google Analytics -->
	<script async src="https://www.googletagmanager.com/gtag/js?id='UA-133422980-2"></script>
	<script>
	  window.dataLayer = window.dataLayer || [];
	  function gtag(){dataLayer.push(arguments);}
	  gtag('js', new Date());

	  gtag('config', 'UA-133422980-2');
	</script>

	<meta charset="utf-8">
	<meta http-equiv="x-ua-compatible" content="ie=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1">

	<title>
		gem5: Adding cache to configuration script 
	</title>

	<!-- SITE FAVICON -->
	<link rel="shortcut icon" type="image/gif" href="/assets/img/gem5ColorVert.gif"/>

	<link rel="canonical" href="http://localhost:4000/documentation/learning_gem5/part1/cache_config/">
	<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,300,700,800,600' rel='stylesheet' type='text/css'>
	<link href='https://fonts.googleapis.com/css?family=Muli:400,300' rel='stylesheet' type='text/css'>

	<!-- FAVICON -->
	<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">

	<!-- BOOTSTRAP -->
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">

	<!-- CUSTOM CSS -->
	<link rel="stylesheet" href="/css/main.css">
</head>


<body>
	<nav class="navbar navbar-expand-md navbar-light bg-light">
  <a class="navbar-brand" href="/">
		<img src="/assets/img/gem5ColorLong.gif" alt="gem5" height=55px>
	</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarNavDropdown">
    <!-- LIST FOR NAVBAR -->
    <ul class="navbar-nav ml-auto">
      <!-- HOME -->
      <li class="nav-item ">
        <a class="nav-link" href="/">Home</a>
      </li>

      <!-- ABOUT -->
			<li class="nav-item dropdown ">
				<a class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
					About
				</a>
				<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
          <a class="dropdown-item" href="/about">About gem5</a>
          <a class="dropdown-item" href="/publications">Publications</a>
          <a class="dropdown-item" href="/governance">Governance</a>
				</div>
			</li>

      <!-- DOCUMENTATION -->
			<li class="nav-item dropdown active">
				<a class="nav-link dropdown-toggle" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
					Documentation
				</a>
				<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
					<!-- Pull navigation from _data/documentation.yml -->
					
            <a class="dropdown-item" href="/documentation">gem5 documentation</a>
					
            <a class="dropdown-item" href="/documentation/learning_gem5/introduction">Learning gem5</a>
					
            <a class="dropdown-item" href="http://doxygen.gem5.org/release/current/index.html">gem5 Doxygen</a>
					
            <a class="dropdown-item" href="/documentation/reporting_problems">Reporting Problems</a>
					
				</div>
			</li>

      <!-- EVENTS -->
			<li class="nav-item dropdown ">
        <a class="nav-link" href="/events/">Events</a>
			</li>

      <!-- CONTRIBUTING -->
      <li class="nav-item ">
        <a class="nav-link" href="/contributing">Contributing</a>
      </li>

      <!-- BLOG -->
      <li class="nav-item ">
        <a class="nav-link" href="/blog">Blog</a>
      </li>

      <!-- SEARCH -->
			<li class="nav-item ">
        <a class="nav-link" href="/search">Search</a>
      </li>
    </ul>
  </div>
</nav>

	<main>
		<div class="sidenav-top">
  <div class="sidenav-brand bg-light">
    <a href="/"><img src="/assets/img/gem5ColorLong.gif" height="55px"></a>
  </div>
  <div class="search">
    <form action="/search" method="get">
      <!-- <label for="search-box"><i class="fa fa-search"></i></label> -->
      <input type="text" name="query">
      <button type="submit" name="submit"><i class="fa fa-search"></i></button>
    </form>
  </div>
</div>
<div class="sidenav">
  <!-- Pull navigation from _data/documentation.yml -->
  
    
  
    
    
      <a class="item" href="/documentation/learning_gem5/introduction" role="button" aria-expanded="false" aria-controls="collapseExample">
        Introduction
      </a>
      <div class="collapse " id="introduction">
        
      </div>
    
      <a class="item" data-toggle="collapse" href="#part1" role="button" aria-expanded="false" aria-controls="collapseExample">
        Getting Started
      </a>
      <div class="collapse show" id="part1">
        
          <a class="subitem " href="/documentation/learning_gem5/part1/building">Building gem5</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/simple_config">Creating a simple configuration script</a>
        
          <a class="subitem active" href="/documentation/learning_gem5/part1/cache_config">Adding cache to configuration script</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/gem5_stats">Understanding gem5 statistics and output</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part1/example_configs">Using the default configuration scripts</a>
        
      </div>
    
      <a class="item" data-toggle="collapse" href="#part2" role="button" aria-expanded="false" aria-controls="collapseExample">
        Modifying/Extending
      </a>
      <div class="collapse " id="part2">
        
          <a class="subitem " href="/documentation/learning_gem5/part2/environment">Setting up your development environment</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/helloobject">Creating a very simple SimObject</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/debugging">Debugging gem5</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/events">Event-driven programming</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/parameters">Adding parameters to SimObjects and more events</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/memoryobject">Creating SimObjects in the memory system</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part2/simplecache">Creating a simple cache object</a>
        
      </div>
    
      <a class="item" data-toggle="collapse" href="#part3" role="button" aria-expanded="false" aria-controls="collapseExample">
        Modeling Cache Coherence with Ruby
      </a>
      <div class="collapse " id="part3">
        
          <a class="subitem " href="/documentation/learning_gem5/part3/MSIintro">Introduction to Ruby</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-intro">MSI example cache protocol</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-declarations">Declaring a state machine</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-in-ports">In port code blocks</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-actions">Action code blocks</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/cache-transitions">Transition code blocks</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/directory">MSI Directory implementation</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/MSIbuilding">Compiling a SLICC protocol</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/configuration">Configuring a simple Ruby system</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/running">Running the simple Ruby system</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/MSIdebugging">Debugging SLICC Protocols</a>
        
          <a class="subitem " href="/documentation/learning_gem5/part3/simple-MI_example">Configuring for a standard protocol</a>
        
      </div>
    
      <a class="item" href="/documentation/learning_gem5/gem5_101/" role="button" aria-expanded="false" aria-controls="collapseExample">
        gem5 101
      </a>
      <div class="collapse " id="gem5_101">
        
      </div>
    
    
  
    
  
    
  
</div>


<div class="container" id="doc-container">
  <div class="edit"><a href="https://gem5.googlesource.com/public/gem5-website/+/refs/heads/master/README.md">Edit this page</a></div>
  <b>authors:</b> Jason Lowe-Power<br>
  

  <br>
  <h1 id="adding-cache-to-the-configuration-script">Adding cache to the configuration script</h1>

<p>Using the <a href="/simple_config">previous configuration script as a starting point</a>,
this chapter will walk through a more complex configuration. We will add
a cache hierarchy to the system as shown in
the figure below. Additionally, this chapter
will cover understanding the gem5 statistics output and adding command
line parameters to your scripts.</p>

<p><img src="/pages/static/figures/advanced_config.png" alt="A system configuration with a two-level cache
hierarchy." /></p>

<h2 id="creating-cache-objects">Creating cache objects</h2>

<p>We are going to use the classic caches, instead of ruby-intro-chapter,
since we are modeling a single CPU system and we don’t care about
modeling cache coherence. We will extend the Cache SimObject and
configure it for our system. First, we must understand the parameters
that are used to configure Cache objects.</p>

<blockquote>
  <p><strong>Classic caches and Ruby</strong></p>

  <p>gem5 currently has two completely distinct subsystems to model the
on-chip caches in a system, the “Classic caches” and “Ruby”. The
historical reason for this is that gem5 is a combination of m5 from
Michigan and GEMS from Wisconsin. GEMS used Ruby as its cache model,
whereas the classic caches came from the m5 codebase (hence
“classic”). The difference between these two models is that Ruby is
designed to model cache coherence in detail. Part of Ruby is SLICC, a
language for defining cache coherence protocols. On the other hand,
the classic caches implement a simplified and inflexible MOESI
coherence protocol.</p>

  <p>To choose which model to use, you should ask yourself what you are
trying to model. If you are modeling changes to the cache coherence
protocol or the coherence protocol could have a first-order impact on
your results, use Ruby. Otherwise, if the coherence protocol isn’t
important to you, use the classic caches.</p>

  <p>A long-term goal of gem5 is to unify these two cache models into a
single holistic model.</p>
</blockquote>

<h3 id="cache">Cache</h3>

<p>The Cache SimObject declaration can be found in src/mem/cache/Cache.py.
This Python file defines the parameters which you can set of the
SimObject. Under the hood, when the SimObject is instantiated these
parameters are passed to the C++ implementation of the object. The
<code class="highlighter-rouge">Cache</code> SimObject inherits from the <code class="highlighter-rouge">BaseCache</code> object shown below.</p>

<p>Within the <code class="highlighter-rouge">BaseCache</code> class, there are a number of <em>parameters</em>. For
instance, <code class="highlighter-rouge">assoc</code> is an integer parameter. Some parameters, like
<code class="highlighter-rouge">write_buffers</code> have a default value, 8 in this case. The default
parameter is the first argument to <code class="highlighter-rouge">Param.*</code>, unless the first argument
is a string. The string argument of each of the parameters is a
description of what the parameter is (e.g.,
<code class="highlighter-rouge">tag_latency = Param.Cycles("Tag lookup latency")</code> means that the
<code class="highlighter-rouge">`tag_latency</code> controls “The hit latency for this cache”).</p>

<p>Many of these parameters do not have defaults, so we are required to set
these parameters before calling <code class="highlighter-rouge">m5.instantiate()</code>.</p>

<hr />

<p>Now, to create caches with specific parameters, we are first going to
create a new file, <code class="highlighter-rouge">caches.py</code>, in the same directory as simple.py,
<code class="highlighter-rouge">configs/tutorial</code>. The first step is to import the SimObject(s) we are
going to extend in this file.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from m5.objects import Cache
</code></pre></div></div>

<p>Next, we can treat the BaseCache object just like any other Python class
and extend it. We can name the new cache anything we want. Let’s start
by making an L1 cache.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class L1Cache(Cache):
    assoc = 2
    tag_latency = 2
    data_latency = 2
    response_latency = 2
    mshrs = 4
    tgts_per_mshr = 20
</code></pre></div></div>

<p>Here, we are setting some of the parameters of the BaseCache that do not
have default values. To see all of the possible configuration options,
and to find which are required and which are optional, you have to look
at the source code of the SimObject. In this case, we are using
BaseCache.</p>

<p>We have extended <code class="highlighter-rouge">BaseCache</code> and set most of the parameters that do not
have default values in the <code class="highlighter-rouge">BaseCache</code> SimObject. Next, let’s two more
sub-classes of L1Cache, an L1DCache and L1ICache</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class L1ICache(L1Cache):
    size = '16kB'

class L1DCache(L1Cache):
    size = '64kB'
</code></pre></div></div>

<p>Let’s also create an L2 cache with some reasonable parameters.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class L2Cache(Cache):
    size = '256kB'
    assoc = 8
    tag_latency = 20
    data_latency = 20
    response_latency = 20
    mshrs = 20
    tgts_per_mshr = 12
</code></pre></div></div>

<p>Now that we have specified all of the necessary parameters required for
<code class="highlighter-rouge">BaseCache</code>, all we have to do is instantiate our sub-classes and
connect the caches to the interconnect. However, connecting lots of
objects up to complex interconnects can make configuration files quickly
grow and become unreadable. Therefore, let’s first add some helper
functions to our sub-classes of <code class="highlighter-rouge">Cache</code>. Remember, these are just Python
classes, so we can do anything with them that you can do with a Python
class.</p>

<p>To the L1 cache let’s add two functions, <code class="highlighter-rouge">connectCPU</code> to connect a CPU
to the cache and <code class="highlighter-rouge">connectBus</code> to connect the cache to a bus. We need to
add the following code to the <code class="highlighter-rouge">L1Cache</code> class.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def connectCPU(self, cpu):
    # need to define this in a base class!
    raise NotImplementedError

def connectBus(self, bus):
    self.mem_side = bus.slave
</code></pre></div></div>

<p>Next, we have to define a separate <code class="highlighter-rouge">connectCPU</code> function for the
instruction and data caches, since the I-cache and D-cache ports have a
different names. Our <code class="highlighter-rouge">L1ICache</code> and <code class="highlighter-rouge">L1DCache</code> classes now become:</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class L1ICache(L1Cache):
    size = '16kB'

    def connectCPU(self, cpu):
        self.cpu_side = cpu.icache_port

class L1DCache(L1Cache):
    size = '64kB'

    def connectCPU(self, cpu):
        self.cpu_side = cpu.dcache_port
</code></pre></div></div>

<p>Finally, let’s add functions to the <code class="highlighter-rouge">L2Cache</code> to connect to the
memory-side and CPU-side bus, respectively.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def connectCPUSideBus(self, bus):
    self.cpu_side = bus.master

def connectMemSideBus(self, bus):
    self.mem_side = bus.slave
</code></pre></div></div>

<p>The full file can be found in the gem5 source at
<code class="highlighter-rouge">gem5/configs/learning_gem5/part1/caches.py</code>.</p>

<h2 id="adding-caches-the-simple-config-file">Adding caches the simple config file</h2>

<p>Now, let’s add the caches we just created to the configuration script we
created in the last chapter &lt;simple-config-chapter&gt;.</p>

<p>First, let’s copy the script to a new name.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>cp ./configs/tutorial/simple.py ./configs/tutorial/two_level.py
</code></pre></div></div>

<p>First, we need to import the names from the <code class="highlighter-rouge">caches.py</code> file into the
namespace. We can add the following to the top of the file (after the
m5.objects import), as you would with any Python source.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from caches import *
</code></pre></div></div>

<p>Now, after creating the CPU, let’s create the L1 caches:</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>system.cpu.icache = L1ICache()
system.cpu.dcache = L1DCache()
</code></pre></div></div>

<p>And connect the caches to the CPU ports with the helper function we
created.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>system.cpu.icache.connectCPU(system.cpu)
system.cpu.dcache.connectCPU(system.cpu)
</code></pre></div></div>

<p>You need to <em>remove</em> the lines which connected the cache
ports directly to the memory bus, replaying them with
the following two lines.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>system.cpu.icache_port = system.membus.slave
system.cpu.dcache_port = system.membus.slave
</code></pre></div></div>

<p>We can’t directly connect the L1 caches to the L2 cache since the L2
cache only expects a single port to connect to it. Therefore, we need to
create an L2 bus to connect our L1 caches to the L2 cache. The, we can
use our helper function to connect the L1 caches to the L2 bus.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>system.l2bus = L2XBar()

system.cpu.icache.connectBus(system.l2bus)
system.cpu.dcache.connectBus(system.l2bus)
</code></pre></div></div>

<p>Next, we can create our L2 cache and connect it to the L2 bus and the
memory bus.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>system.l2cache = L2Cache()
system.l2cache.connectCPUSideBus(system.l2bus)

system.l2cache.connectMemSideBus(system.membus)
</code></pre></div></div>

<p>Everything else in the file stays the same! Now we have a complete
configuration with a two-level cache hierarchy. If you run the current
file, <code class="highlighter-rouge">hello</code> should now finish in 58513000 ticks. The full script can
be found in the gem5 source at
<code class="highlighter-rouge">gem5/configs/learning_gem5/part1/two_level.py</code>.</p>

<h2 id="adding-parameters-to-your-script">Adding parameters to your script</h2>

<p>When performing experiments with gem5, you don’t want to edit your
configuration script every time you want to test the system with
different parameters. To get around this, you can add command-line
parameters to your gem5 configuration script. Again, because the
configuration script is just Python, you can use the Python libraries
that support argument parsing. Although :pyoptparse is officially
deprecated, many of the configuration scripts that ship with gem5 use it
instead of pyargparse since gem5’s minimum Python version used to be
2.5. The minimum Python version is now 2.7, so pyargparse is a better
option when writing new scripts that don’t need to interact with the
current gem5 scripts. To get started using :pyoptparse, you can consult
the online Python documentation.</p>

<p>To add options to our two-level cache configuration, after importing our
caches, let’s add some options.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from optparse import OptionParser

parser = OptionParser()
parser.add_option('--l1i_size', help="L1 instruction cache size")
parser.add_option('--l1d_size', help="L1 data cache size")
parser.add_option('--l2_size', help="Unified L2 cache size")

(options, args) = parser.parse_args()
</code></pre></div></div>

<p>Now, you can run
<code class="highlighter-rouge">build/X86/gem5.opt configs/tutorial/two_level.py --help</code> which
will display the options you just added.</p>

<p>Next, we need to pass these options onto the caches that we create in
the configuration script. To do this, we’ll simply change two_level.py
to pass the options into the caches as a parameter to their constructor
and add an appropriate constructor, next.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>system.cpu.icache = L1ICache(options)
system.cpu.dcache = L1DCache(options)
...
system.l2cache = L2Cache(options)
</code></pre></div></div>

<p>In caches.py, we need to add constructors (<code class="highlighter-rouge">__init__</code> functions in
Python) to each of our classes. Starting with our base L1 cache, we’ll
just add an empty constructor since we don’t have any parameters which
apply to the base L1 cache. However, we can’t forget to call the super
class’s constructor in this case. If the call to the super class
constructor is skipped, gem5’s SimObject attribute finding function will
fail and the result will be
“<code class="highlighter-rouge">RuntimeError: maximum recursion depth exceeded</code>” when you try to
instantiate the cache object. So, in <code class="highlighter-rouge">L1Cache</code> we need to add the
following after the static class members.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def __init__(self, options=None):
    super(L1Cache, self).__init__()
    pass
</code></pre></div></div>

<p>Next, in the <code class="highlighter-rouge">L1ICache</code>, we need to use the option that we created
(<code class="highlighter-rouge">l1i_size</code>) to set the size. In the following code, there is guards for
if <code class="highlighter-rouge">options</code> is not passed to the <code class="highlighter-rouge">L1ICache</code> constructor and if no
option was specified on the command line. In these cases, we’ll just use
the default we’ve already specified for the size.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def __init__(self, options=None):
    super(L1ICache, self).__init__(options)
    if not options or not options.l1i_size:
        return
    self.size = options.l1i_size
</code></pre></div></div>

<p>We can use the same code for the <code class="highlighter-rouge">L1DCache</code>:</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def __init__(self, options=None):
    super(L1DCache, self).__init__(options)
    if not options or not options.l1d_size:
        return
    self.size = options.l1d_size
</code></pre></div></div>

<p>And the unified <code class="highlighter-rouge">L2Cache</code>:</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def __init__(self, options=None):
    super(L2Cache, self).__init__()
    if not options or not options.l2_size:
        return
    self.size = options.l2_size
</code></pre></div></div>

<p>With these changes, you can now pass the cache sizes into your script
from the command line like below.</p>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>build/X86/gem5.opt configs/tutorial/two_level.py --l2_size='1MB' --l1d_size='128kB'
</code></pre></div></div>

<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gem5 Simulator System.  http://gem5.org
gem5 is copyrighted software; use the --copyright option for details.

gem5 compiled Sep  6 2015 14:17:02
gem5 started Sep  6 2015 15:06:51
gem5 executing on galapagos-09.cs.wisc.edu
command line: build/X86/gem5.opt ../tutorial/_static/scripts/part1/two_level_opts.py --l2_size=1MB --l1d_size=128kB

Global frequency set at 1000000000000 ticks per second
warn: DRAM device capacity (8192 Mbytes) does not match the address range assigned (512 Mbytes)
0: system.remote_gdb.listener: listening for remote gdb #0 on port 7000
Beginning simulation!
info: Entering event queue @ 0.  Starting simulation...
Hello world!
Exiting @ tick 56742000 because target called exit()
</code></pre></div></div>

<p>The full scripts can be found in the gem5 source at
<code class="highlighter-rouge">gem5/configs/learning_gem5/part1/caches.py</code> and
<code class="highlighter-rouge">gem5/configs/learning_gem5/part1/two_level.py</code>.</p>

  <br>

  <!-- RETRIVE PREVIOUS PAGE LINK -->
  
    
  
    
  
    
  
    
  

  <!-- RETRIEVE NEXT PAGE LINK -->
  
    
  
    
  
    
  
    
  


  <div class="navbuttons">
    
      <a href=""><button type="button" class="btn btn-outline-primary">PREVIOUS</button></a>
    

    
      <a href=""><button type="button" class="btn btn-outline-primary">NEXT</button></a>
    
  </div>
</div>

	</main>
	<footer class="page-footer">
	<div class="container">
		<div class="row">

			<div class="col-12 col-sm-4">
				<p>gem5</p>
				<p><a href="/about">About</a></p>
				<p><a href="/publications">Publications</a></p>
				<p><a href="/contributing">Contributing</a></p>
				<p><a href="/governance">Governance</a></p>
			<br></div>

			<div class="col-12 col-sm-4">
				<p>Docs</p>
				<p><a href="/documentation">Documentation</a></p>
				<p><a href="http://gem5.org/Documentation">Old Documentation</a></p>
				<p><a href="https://gem5.googlesource.com/public/gem5">Source</a></p>
			<br></div>

			<div class="col-12 col-sm-4">
				<p>Help</p>
				<p><a href="/search">Search</a></p>
				<p><a href="/mailing_lists">Mailing Lists</a></p>
				<p><a href="https://gem5.googlesource.com/public/gem5-website/+/refs/heads/master/README.md">Website Source</a></p>
			<br></div>

		</div>
	</div>
</footer>


	<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
	<script src="https://unpkg.com/commentbox.io/dist/commentBox.min.js"></script>

	<script>
	  // When the user scrolls down 20px from the top of the document, show the button
	  window.onscroll = function() {scrollFunction()};

	  function scrollFunction() {
	      if (document.body.scrollTop > 100 || document.documentElement.scrollTop > 20) {
	          document.getElementById("myBtn").style.display = "block";
	      } else {
	          document.getElementById("myBtn").style.display = "none";
	      }
	  }

	  // When the user clicks on the button, scroll to the top of the document
	  function topFunction() {
	      document.body.scrollTop = 0;
	      document.documentElement.scrollTop = 0;
	  }

		import commentBox from 'commentbox.io';
		// or
		const commentBox = require('commentbox.io');
		// or if using the CDN, it will be available as a global "commentBox" variable.

		commentBox('my-project-id');

	</script>

</body>


</html>
